package com.sy.simpleegg.platform.whm.cmd

import android.util.Log
import com.sy.simpleegg.platform.whm.MQConfig
import com.sy.simpleegg.platform.whm.util.DESUtil
import com.sy.simpleegg.util.GsonUtil
import com.sy.logger.Logger
import java.util.Arrays
import java.util.Locale

object CmdProducter {
    private const val TAG = "CmdProducter"

    //    public static String loginMsg(String transVer, String softwareVer, String devicePassword){
    //        String result = null;
    //        try {
    //            //随机数
    //            String random = CmdAssistant.getMsgNumber();
    //            //通讯版本
    //            String transVerHex = CmdAssistant.str2hex(transVer, 8);
    //            //软件版本
    //            String softwareVerHex = CmdAssistant.str2hex(softwareVer, 8);
    //            //设备密码
    //            String devicePasswordHex = CmdAssistant.str2hex(devicePassword, 8);
    //
    //            //转为字节数组
    //            byte[] randomBytes = CmdAssistant.hexToByteArray(random);
    //            byte[] cmdFlagBytes = CmdAssistant.hexToByteArray(CMD_LOGIN);
    //            byte[] transVerBytes = CmdAssistant.hexToByteArray(transVerHex);
    //            byte[] softwareVerBytes = CmdAssistant.hexToByteArray(softwareVerHex);
    //            byte[] devicePasswordBytes = CmdAssistant.hexToByteArray(devicePasswordHex);
    //            byte[] devTypeBytes = CmdAssistant.hexToByteArray(DEVICE_TYPE);
    //            byte[] addBytes = new byte[randomBytes.length + cmdFlagBytes.length + transVerBytes.length + softwareVerBytes.length + devicePasswordBytes.length + devTypeBytes.length];
    //            //拼接成一个数组
    //            System.arraycopy(randomBytes, 0, addBytes, 0, randomBytes.length);
    //            System.arraycopy(cmdFlagBytes, 0, addBytes, randomBytes.length, cmdFlagBytes.length);
    //            System.arraycopy(transVerBytes, 0, addBytes, randomBytes.length + cmdFlagBytes.length, transVerBytes.length);
    //            System.arraycopy(softwareVerBytes, 0, addBytes, randomBytes.length + cmdFlagBytes.length + transVerBytes.length, softwareVerBytes.length);
    //            System.arraycopy(devicePasswordBytes, 0, addBytes, randomBytes.length + cmdFlagBytes.length + transVerBytes.length + softwareVerBytes.length, devicePasswordBytes.length);
    //            System.arraycopy(devTypeBytes, 0, addBytes, randomBytes.length + cmdFlagBytes.length + transVerBytes.length + softwareVerBytes.length + devicePasswordBytes.length, devTypeBytes.length);
    //            //计算校验码
    //            int checkAdd = CmdAssistant.addByte(addBytes);
    //            //校验码
    //            String checkHex = Integer.toHexString(checkAdd).toUpperCase();
    //            while (checkHex.length() < 4){
    //                checkHex = "0" + checkHex;
    //            }
    //            checkHex = checkHex.substring(0, 4);
    //
    //            //数据长度 = 校验位 + 随机数 + 命令 + 数据包 + 设备类型
    //            int encryptHexLen = CmdAssistant.hexToByteArray(checkHex).length + addBytes.length;
    //            String lenHex = Integer.toHexString(encryptHexLen);
    //            while(lenHex.length() < 2){
    //                lenHex = "0" + lenHex;
    //            }
    //            lenHex = lenHex.substring(0, 2);
    //
    //            //加密数据
    //            String encryptHexStr = checkHex + random + CMD_LOGIN + transVerHex + softwareVerHex + devicePasswordHex + DEVICE_TYPE;
    //            String encryptData = DESUtil.encode(KEY, encryptHexStr.replace(" ", ""));
    //
    //            //最终数据 = 数据头 + 数据长度 + 数据加密包（校验码+随机数+命令号+数据+设备类型）
    //            result = HEAD + lenHex + encryptData;
    //
    //            result = HEAD + lenHex + encryptData;
    //        } catch (NumberFormatException e) {
    //            e.printStackTrace();
    //            Log.e(TAG, "创建登录指令异常：" + e.getMessage());
    //        }
    //
    //        return result;
    //    }
    fun loginMessage(transVer: String, softwareVer: String, devicePassword: String): ByteArray? {
        Logger.d("登录")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER1,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),
            CmdParamBean(MQConfig.CMD_LOGIN, 1, true),
            CmdParamBean(transVer, 8),
            CmdParamBean(softwareVer, 8),
            CmdParamBean(devicePassword, 8),
            CmdParamBean(MQConfig.DEVICE_TYPE, 1, true)
        )
    }

    fun deviceInit(
        netTypeHex: String,
        devFlag: String,
        netModule: String,
        locationType: String,
        locationMsg: String,
        firmwareVer: String
    ): ByteArray? {
        Logger.d("设备初始化")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER1,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_INIT, 1, true),  //命令号
            CmdParamBean(netTypeHex, 1, true),  //入网方式
            CmdParamBean(devFlag, -20),  //设备唯一标识
            CmdParamBean(netModule, 10),  //入网设备型号
            CmdParamBean(locationType, 1, true),  //定位类型
            CmdParamBean(locationMsg, 24),  //定位信息
            CmdParamBean(firmwareVer, 8),  //固件版本
            CmdParamBean("00", 8) //保留数据
        )
    }

    //    public static byte[] heartBeat(String devState, String signal, String devErr){
    //        Log.d(TAG, "设备心跳");
    //        return getMsgBody(
    //                null, //附加数据
    //                MQConfig.PROTOCOL_VER1,
    //                new CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),//随机数
    //                new CmdParamBean(CMD_HEARTBEAT, 1, true),//命令号
    //                new CmdParamBean(devState, 1, true),//设备状态
    //                new CmdParamBean(signal, 1),//设备信号
    //                new CmdParamBean(devErr, 1)//故障
    //        );
    //    }
    fun heartBeat(devState: Int, signal: Int, devErr: Int): ByteArray? {
        Log.d(TAG, "设备心跳")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER1,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_HEARTBEAT, 1, true),  //命令号
            CmdParamBean(devState, 1, true),  //设备状态
            CmdParamBean(signal, 1, true),  //设备信号
            CmdParamBean(devErr, 1, true) //故障
        )
    }

    /**
     * 订单响应消息
     * @param coinCount
     * @param orderNumber
     * @param orderState
     * @param rejectReason
     * @return
     */
    fun orderRepMessage(
        coinCount: Int,
        orderNumber: String,
        orderState: Int,
        rejectReason: Int
    ): ByteArray? {
        Logger.d("订单响应")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_RESPON_ORDER, 2, true),  //命令号
            CmdParamBean(orderNumber, -32, false),  //订单号
            CmdParamBean(orderState, 1, true),  //订单状态
            CmdParamBean(rejectReason, 1, true),  //拒绝原因
            CmdParamBean(coinCount, 3, true) //出币数量
        )
    }

    /**
     * 获取套餐数量
     * @return
     */
    fun getPackageCount(packageType: Int): ByteArray? {
        Logger.d("获取套餐数量")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_GET_PACKAGE, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(packageType, 1, true),  //套餐类型
            CmdParamBean(0, 1, true),  //套餐开始序号
            CmdParamBean(0, 1, true) //套餐数量
        )
    }

    fun getPackage(count: Int, packageType: Int): ByteArray? {
        Logger.d("获取套餐数据")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_GET_PACKAGE, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(packageType, 1, true),  //套餐类型 1-普通套餐 2-会员兑币套餐
            CmdParamBean(1, 1, true),  //套餐开始序号
            CmdParamBean(count, 1, true) //套餐数量
        )
    }

    fun postBackscan(
        pkgId: Int,
        payType: Int,
        business: Int,
        pkgType: Int,
        data: String
    ): ByteArray? {
        Logger.d("上报反扫数据")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_POST_BACKSCAN, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(business, 2, true),  //业务类型
            CmdParamBean(pkgType, 1, true),  //套餐类型
            CmdParamBean(pkgId, 4, true),  //套餐id
            CmdParamBean(payType, 1, true),  //支付方式
            CmdParamBean(data, -1, false) //反扫数据
        )
    }

    fun postBill(moneyDatas: IntArray): ByteArray? {
        Logger.d("上报投钞数据")
        val beanList: MutableList<CmdParamBean> = ArrayList()
        var denominationCount = 0
        for (i in moneyDatas.indices) {
            if (moneyDatas[i] > 0) {
                denominationCount++
                val moneyType = CmdParamBean(1, 1, true) //货币类型 1-纸钞 2-硬币
                val money = CmdParamBean(MQConfig.MONEY[i], 3, true) //面额
                val moneyCount = CmdParamBean(moneyDatas[i], 3, true) //数量
                beanList.add(moneyType)
                beanList.add(money)
                beanList.add(moneyCount)
            }
        }
        return getMsgBody(
            beanList,  //进钞数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_POST_BILL, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(denominationCount, 1, true) //数据条数（投钞数据条数）
        )
    }

    fun postBill(moneyDatas: IntArray, msgNumber: Int): ByteArray? {
        Logger.d("上报投钞数据")
        val beanList: MutableList<CmdParamBean> = ArrayList()
        var denominationCount = 0
        for (i in moneyDatas.indices) {
            if (moneyDatas[i] > 0) {
                denominationCount++
                val moneyType = CmdParamBean(1, 1, true) //货币类型 1-纸钞 2-硬币
                val money = CmdParamBean(MQConfig.MONEY[i], 3, true) //面额
                val moneyCount = CmdParamBean(moneyDatas[i], 3, true) //数量
                beanList.add(moneyType)
                beanList.add(money)
                beanList.add(moneyCount)
            }
        }
        return getMsgBody(
            beanList,  //进钞数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_POST_BILL, 2, true),  //命令号
            CmdParamBean(Integer.toHexString(msgNumber), 1, true),  //消息编号
            CmdParamBean(denominationCount, 1, true) //数据条数（投钞数据条数）
        )
    }

    fun getPayCode(pkgId: Int): ByteArray? {
        Logger.d("获取支付二维码")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_GET_PAY_CODE, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(1, 2, true),  //业务类型
            CmdParamBean(pkgId, 4, true),  //套餐id
            CmdParamBean(0, 1, true) //支付方式
        )
    }

    fun getPayCode(pkgId: Int, payType: Int, packageType: Int): ByteArray? {
        Logger.d("获取支付二维码")
        return getMsgBody(
            null,  //附加数据
            MQConfig.PROTOCOL_VER2,
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
            CmdParamBean(MQConfig.CMD_GET_PAY_CODE, 2, true),  //命令号
            CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
            CmdParamBean(1, 2, true),  //业务类型
            CmdParamBean(packageType, 1, true),  //套餐类型
            CmdParamBean(pkgId, 4, true),  //套餐id
            CmdParamBean(payType, 1, true) //支付方式
        )
    }

    val tipsRep: ByteArray?
        get() {
            Logger.d("获取提示信息上报")
            return getMsgBody(
                null,  //附加数据
                MQConfig.PROTOCOL_VER2,
                CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
                CmdParamBean(MQConfig.CMD_RESPON_TIPS, 2, true),  //命令号
                CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //消息编号
                CmdParamBean(1, 1, true) //接收状态
            )
        }
    val withdrawalCode: ByteArray?
        get() {
            Logger.d("获取会员提币码")
            return getMsgBody(
                null,  //附加数据
                MQConfig.PROTOCOL_VER2,
                CmdParamBean(CmdAssistant.getMsgNumber(), 1, true),  //随机数
                CmdParamBean(MQConfig.CMD_GET_WITHDRAWAL_CODE, 2, true) //命令号
                //                new CmdParamBean(CmdAssistant.getMsgNumber(), 1, true)//消息编号
            )
        }

    /**
     * 创建消息内容
     * @param protocolVer 协议版本
     * @param params 消息参数
     * @return
     */
    private fun getMsgBody(
        cmdParamBeanList: List<CmdParamBean>?,
        protocolVer: String,
        vararg params: CmdParamBean?
    ): ByteArray? {
        var params = params
        if (params.size == 0) {
            Log.d(TAG, "no argument passed")
        }
        if (cmdParamBeanList != null && cmdParamBeanList.size > 0) {
            val cmdParamBeanArr = arrayOfNulls<CmdParamBean>(params.size + cmdParamBeanList.size)
            System.arraycopy(params, 0, cmdParamBeanArr, 0, params.size)
            for (i in params.size until cmdParamBeanArr.size) {
                cmdParamBeanArr[i] = cmdParamBeanList[i - params.size]
            }
            params = cmdParamBeanArr
            Log.d(TAG, "补充附加数据后的完整数据：" + GsonUtil.getInstance()!!.toJson(params))
        }
        var result: ByteArray? = null
        try {
            val paramHexList: MutableList<String?> = ArrayList()
            var addBytes = ByteArray(0)
            Log.d(TAG, "params长度=：" + params.size)
            //每个参数转为16进制字符串
            for (param in params) {
                var paramHex: String? = null

                //param.len < -1 在后面补00  param.len == -1 不需要补00 param.len > 0 前面补00
                if (!param!!.isHexString) {
                    Log.d(TAG, "param.content=" + param.content + " len=" + param.len)
                    if (param.content is String) {
                        if (param.len != -1) {
                            if (param.len > 0) {
                                paramHex = CmdAssistant.str2hex(param.content as String, param.len)
                            } else {
                                val len = Math.abs(param.len)
                                paramHex = CmdAssistant.str2hex(param.content as String)
                                paramHex = addZeroRight(paramHex, len)
                            }
                        } else {
                            //不需要补00
                            paramHex = CmdAssistant.str2hex(param.content as String)
                        }
                    }
                } else {
                    if (param.content is String) {
                        val paramStr = param.content as String
                        val len = Math.abs(param.len)
                        paramHex = if (paramStr.length < len * 2) {
                            if (param.len < -1) {
                                addZeroRight(paramStr, len)
                            } else {
                                addZero(paramStr, param.len)
                            }
                        } else {
                            paramStr
                        }
                    } else if (param.content is Int) {
                        val paramInt = param.content as Int
                        //                        String paramStr = CmdAssistant.byteArrayToHexStr(new byte[]{(byte) paramInt});
                        val paramStr = Integer.toHexString(paramInt).uppercase(Locale.getDefault())
                        val len = Math.abs(param.len)
                        paramHex = if (paramStr.length < len * 2) {
                            if (param.len < -1) {
                                addZeroRight(paramStr, len)
                            } else {
                                addZero(paramStr, param.len)
                            }
                        } else {
                            paramStr
                        }
                        Log.d(TAG, "int类型param=$paramInt")
                        Log.d(TAG, "int类型paramHex=$paramHex")
                    } else if (param.content is Char) {
                        val paramChar = param.content as Char
                        val bytes = CmdAssistant.charsTobytes(charArrayOf(paramChar))
                        paramHex = CmdAssistant.byteArrayToHexStr(bytes)
                        paramHex = addZero(paramHex, param.len)
                        Log.d(TAG, "char类型param=$paramChar")
                        Log.d(TAG, "char类型paramHex=$paramHex")
                    }
                }
                val paramBytes = CmdAssistant.hexToByteArray(paramHex!!)
                Log.d(TAG, "paramBytes" + Arrays.toString(paramBytes))
                paramHexList.add(paramHex)
                val temp = ByteArray(addBytes.size + paramBytes!!.size)
                if (addBytes.size < 1) {
                    System.arraycopy(paramBytes, 0, temp, 0, paramBytes.size)
                } else {
                    System.arraycopy(addBytes, 0, temp, 0, addBytes.size)
                    System.arraycopy(paramBytes, 0, temp, addBytes.size, paramBytes.size)
                }
                addBytes = temp
            }
            Log.d(TAG, "校验数据Hex：" + CmdAssistant.byteArrayToHexStr(addBytes))
            //计算校验码
            val checkAdd = CmdAssistant.addByte(addBytes)
            val checkHex = CmdAssistant.highLow(checkAdd)
            //            String checkHex = CmdAssistant.convertHighLow(checkAdd);
            Log.d(TAG, "校验码：$checkHex")

            //加密数据
            val sb = StringBuilder()
            for (hexStr in paramHexList) {
                sb.append(hexStr)
            }
            val encryptHexStr = checkHex + sb.toString().trim { it <= ' ' }
            Log.d(TAG, "未加密数据=$encryptHexStr")
            //            Logger.d("未加密的发送数据=" + encryptHexStr);
//            String encryptData = DESUtil.encode(KEY, encryptHexStr.replace(" ", ""));
//
//            result = HEAD + lenHex + encryptData;
            val encryptData = DESUtil.encode3(MQConfig.KEY, encryptHexStr.replace(" ", ""))
            Log.d(TAG, "加密数据=" + Arrays.toString(encryptData))

            //数据长度 = 加密后数据的长度
            val encryptHexLen = CmdAssistant.byteArrayToHexStr(encryptData)!!.length
            var lenHex = Integer.toHexString(encryptHexLen / 2)
            //根据版本号，比配命令号长度，字节
            var cmdLen = 0
            if (MQConfig.PROTOCOL_VER1 == protocolVer) {
                cmdLen = 1
            } else if (MQConfig.PROTOCOL_VER2 == protocolVer) {
                cmdLen = 3
            }
            while (lenHex.length < cmdLen * 2) {
                lenHex = "0$lenHex"
            }
            lenHex = lenHex.substring(0, cmdLen * 2)
            val lenByteArr = CmdAssistant.hexToByteArray(lenHex)
            val headByteArr = CmdAssistant.hexToByteArray(MQConfig.HEAD)
            result = combineByteArray(combineByteArray(headByteArr!!, lenByteArr!!), encryptData)
            Log.d(TAG, "result=" + Arrays.toString(result))
            Log.d(TAG, "resultHex=" + CmdAssistant.byteArrayToHexStr(result))
        } catch (e: Exception) {
            e.printStackTrace()
            Logger.e("创建指令异常：" + e.message)
        }
        return result
    }

    /**
     * 补全数据
     * @param content
     * @param len
     * @return
     */
    private fun addZero(content: String?, len: Int): String {
        return try {
            val result = StringBuilder(content)
            val count = len * 2 - content!!.length
            for (i in 0 until count) {
                result.insert(0, "0")
            }
            result.toString()
        } catch (e: Exception) {
            e.printStackTrace()
            Logger.e("addZero()异常：" + e.message)
            ""
        }
    }

    private fun addZeroRight(content: String?, len: Int): String? {
        var result = content
        try {
            val count = len * 2 - content!!.length
            for (i in 0 until count) {
                result += "0"
            }
        } catch (e: Exception) {
            e.printStackTrace()
            Logger.e("addZeroRight()异常：" + e.message)
        }
        return result
    }

    fun combineByteArray(a: ByteArray, b: ByteArray): ByteArray {
        val combine = ByteArray(a.size + b.size)
        System.arraycopy(a, 0, combine, 0, a.size)
        System.arraycopy(b, 0, combine, a.size, b.size)
        return combine
    }
}
